<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
 <head>
  <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  <title>回退（Backed）枚举</title>
<link media="all" rel="stylesheet" type="text/css" href="styles/03e73060321a0a848018724a6c83de7f-theme-base.css" />
<link media="all" rel="stylesheet" type="text/css" href="styles/03e73060321a0a848018724a6c83de7f-theme-medium.css" />

 </head>
 <body class="docs"><div class="navbar navbar-fixed-top">
  <div class="navbar-inner clearfix">
    <ul class="nav" style="width: 100%">
      <li style="float: left;"><a href="language.enumerations.basics.html">« 枚举基础</a></li>
      <li style="float: right;"><a href="language.enumerations.methods.html">枚举方法 »</a></li>
    </ul>
  </div>
</div>
<div id="breadcrumbs" class="clearfix">
  <ul class="breadcrumbs-container">
    <li><a href="index.html">PHP Manual</a></li>
    <li><a href="language.enumerations.html">枚举</a></li>
    <li>回退（Backed）枚举</li>
  </ul>
</div>
<div id="layout">
  <div id="layout-content"><div id="language.enumerations.backed" class="sect1">
  <h2 class="title">回退（Backed）枚举</h2>

  <p class="para">
   默认情况下枚举条目实现形式不是标量。
   它们是纯粹的对象实例。
   不过，很多时候也需要在数据库、数据存储对象中来回读写枚举条目。
   因此，能够内置支持标量形式也很有用（更易序列化）。
  </p>

  <p class="para">按以下语法，定义标量形式的枚举：</p>

  <div class="example-contents">
   <div class="phpcode"><code><span style="color: #000000">
<span style="color: #0000BB">&lt;?php<br />enum&nbsp;Suit</span><span style="color: #007700">:&nbsp;</span><span style="color: #0000BB">string<br /></span><span style="color: #007700">{<br />&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;</span><span style="color: #0000BB">Hearts&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #DD0000">'H'</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;</span><span style="color: #0000BB">Diamonds&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #DD0000">'D'</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;</span><span style="color: #0000BB">Clubs&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #DD0000">'C'</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;</span><span style="color: #0000BB">Spades&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #DD0000">'S'</span><span style="color: #007700">;<br />}<br /></span><span style="color: #0000BB">?&gt;</span>
</span>
</code></div>
  </div>


  <p class="para">
   由于有标量的条目回退（Backed）到一个更简单值，又叫回退条目（Backed Case）。
   包含所有回退条目的 Enum 又叫“回退 Enum”（Backed Enum）。
   回退 Enum 只能包含回退条目。
   纯粹 Enum 只能包含纯粹条目。
  </p>

  <p class="para">
   回退枚举仅能回退到 <code class="literal">int</code> 或 <code class="literal">string</code> 里的一种类型，
   且同时仅支持使用一种类型（就是说，不能联合 <code class="literal">int|string</code>）。
   如果枚举为标量形式，所有的条目必须明确定义唯一的标量值。
   无法自动生成标量（比如：连续的数字）。
   回退条目必须是唯一的；两个回退条目不能有相同的标量。
   然而，也可以用常量引用到条目，实际上是创建了个别名。
   参见 <a href="language.enumerations.constants.html" class="link">枚举常量</a>。
  </p>

  <p class="para">
   条目等同的值，必须是个字面量或它的表达式。
   不能是常量和常量表达式。
   换言之，允许 <code class="literal">1 + 1</code>，
   不允许 <code class="literal">1 + SOME_CONST</code>。
  </p>

  <p class="para">
   回退条目有个额外的只读属性 <code class="literal">value</code>，
   它是定义时指定的值。
  </p>

  <div class="example-contents">
   <div class="phpcode"><code><span style="color: #000000">
<span style="color: #0000BB">&lt;?php<br /></span><span style="color: #007700">print&nbsp;</span><span style="color: #0000BB">Suit</span><span style="color: #007700">::</span><span style="color: #0000BB">Clubs</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">value</span><span style="color: #007700">;<br /></span><span style="color: #FF8000">//&nbsp;输出&nbsp;"C"<br /></span><span style="color: #0000BB">?&gt;</span>
</span>
</code></div>
  </div>


  <p class="para">
   为了确保 <code class="literal">value</code> 的只读性，
   无法将变量传引用给它。
   也就是说，以下会抛出错误：
  </p>

  <div class="example-contents">
   <div class="phpcode"><code><span style="color: #000000">
<span style="color: #0000BB">&lt;?php<br />$suit&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">Suit</span><span style="color: #007700">::</span><span style="color: #0000BB">Clubs</span><span style="color: #007700">;<br /></span><span style="color: #0000BB">$ref&nbsp;</span><span style="color: #007700">=&nbsp;&amp;</span><span style="color: #0000BB">$suit</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">value</span><span style="color: #007700">;<br /></span><span style="color: #FF8000">//&nbsp;Error:&nbsp;Cannot&nbsp;acquire&nbsp;reference&nbsp;to&nbsp;property&nbsp;Suit::$value<br /></span><span style="color: #0000BB">?&gt;</span>
</span>
</code></div>
  </div>


  <p class="para">
   回退枚举实现了内置的 <span class="interfacename"><a href="class.backedenum.html" class="interfacename">BackedEnum</a></span> interface，
   暴露了两个额外的方法：
  </p>

  <ul class="simplelist">
   <li class="member">
    <code class="literal">from(int|string): self</code> 能够根据标量返回对应的枚举条目。
    如果找不到该值，会抛出 <span class="classname"><a href="class.valueerror.html" class="classname">ValueError</a></span>。
    主要用于输入标量为可信的情况，使用一个不存在的枚举值，可以考虑为需终止应用的错误。
   </li>
   <li class="member">
    <code class="literal">tryFrom(int|string): ?self</code> 能够根据标量返回对应的枚举条目。
    如果找不到该值，会返回 <code class="literal">null</code>。
    主要用于输入标量不可信的情况，调用者需要自己实现默认值的逻辑或错误的处理。
   </li>
  </ul>

  <p class="para">
   <code class="literal">from()</code> 和 <code class="literal">tryFrom()</code> 方法也遵循基本的严格/松散类型规则。
   系统在弱类型模式下接受传入 integer 和 string，并自动强制转换对应值。
   传入 float 也能运行，并且强制转换。
   在严格类型模式下，为 string 回退枚举的 <code class="literal">from()</code> 传入 integer 会导致
   <span class="classname"><a href="class.typeerror.html" class="classname">TypeError</a></span>，反之亦然；float 都会出现有问题。
   其他所有的参数类型，在以上所有模式中都会抛出 TypeError。
  </p>

  <div class="example-contents">
   <div class="phpcode"><code><span style="color: #000000">
<span style="color: #0000BB">&lt;?php<br />$record&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">get_stuff_from_database</span><span style="color: #007700">(</span><span style="color: #0000BB">$id</span><span style="color: #007700">);<br />print&nbsp;</span><span style="color: #0000BB">$record</span><span style="color: #007700">[</span><span style="color: #DD0000">'suit'</span><span style="color: #007700">];<br /><br /></span><span style="color: #0000BB">$suit&nbsp;</span><span style="color: #007700">=&nbsp;&nbsp;</span><span style="color: #0000BB">Suit</span><span style="color: #007700">::</span><span style="color: #0000BB">from</span><span style="color: #007700">(</span><span style="color: #0000BB">$record</span><span style="color: #007700">[</span><span style="color: #DD0000">'suit'</span><span style="color: #007700">]);<br /></span><span style="color: #FF8000">//&nbsp;无效数据抛出&nbsp;ValueError："X"&nbsp;is&nbsp;not&nbsp;a&nbsp;valid&nbsp;scalar&nbsp;value&nbsp;for&nbsp;enum&nbsp;"Suit"<br /></span><span style="color: #007700">print&nbsp;</span><span style="color: #0000BB">$suit</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">value</span><span style="color: #007700">;<br /><br /></span><span style="color: #0000BB">$suit&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">Suit</span><span style="color: #007700">::</span><span style="color: #0000BB">tryFrom</span><span style="color: #007700">(</span><span style="color: #DD0000">'A'</span><span style="color: #007700">)&nbsp;??&nbsp;</span><span style="color: #0000BB">Suit</span><span style="color: #007700">::</span><span style="color: #0000BB">Spades</span><span style="color: #007700">;<br /></span><span style="color: #FF8000">//&nbsp;无效数据返回&nbsp;null，因此会用&nbsp;Suit::Spades&nbsp;代替。<br /></span><span style="color: #007700">print&nbsp;</span><span style="color: #0000BB">$suit</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">value</span><span style="color: #007700">;<br /></span><span style="color: #0000BB">?&gt;</span>
</span>
</code></div>
  </div>


  <p class="para">手动为回退枚举定义 <code class="literal">from()</code> 或 <code class="literal">tryFrom()</code> 方法会导致 fatal 错误。</p>

 </div></div></div></body></html>